package com.small.site.ibase.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.small.site.ibase.IBaseService;
import com.small.site.vo.PageVo;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;
import tk.mybatis.mapper.entity.Example;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * @author xiaochi
 * @date 2021/11/21 22:09
 * @desc BaseServiceImpl
 */
public abstract class BaseServiceImpl<T> implements IBaseService<T> {

    @Autowired
    protected Mapper<T> mapper;
    @Autowired
    protected MySqlMapper<T> mySqlMapper;
    @Autowired
    protected SqlSessionFactory sqlSessionFactory;

    /**
     * 根据主键查询
     * @param id 主键
     * @return 实体对象
     */
    @Override
    public T findOne(Serializable id) {
        return mapper.selectByPrimaryKey(id);
    }

    /**
     * 根据实体对象查询
     * @param t 实体
     * @return 实体对象
     */
    @Override
    public T findOne(T t) {
        return mapper.selectOne(t);
    }

    /**
     * 查询全部
     * @return 实体对象集合
     */
    @Override
    public List<T> findAll() {
        return mapper.selectAll();
    }

    /**
     * 根据条件查询列表
     * @param t 查询条件对象
     * @return List<T>
     */
    @Override
    public List<T> findByWhere(T t) {
        return mapper.select(t);
    }

    /**
     * 根据复杂条件查询列表
     * @param example 查询条件对象
     * @return List<T>
     */
    @Override
    public List<T> findByWhere(Example example){
        return mapper.selectByExample(example);
    }

    /**
     * 分页查询列表
     * @param page 页号
     * @param size 页大小
     * @return 分页实体对象
     */
    @Override
    public PageVo<T> findPage(Integer page, Integer size) {
        PageInfo<T> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> mapper.selectAll());
        return new PageVo<T>(pageInfo);
    }

    /**
     * 根据条件分页查询列表
     * @param page 页号
     * @param size 页大小
     * @param t    查询条件对象
     * @return 分页实体对象
     */
    @Override
    public PageVo<T> findPage(Integer page, Integer size, T t) {
        PageInfo<T> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> mapper.select(t));
        return new PageVo<T>(pageInfo);
    }

    /**
     * 根据复杂条件分页查询列表
     * @param page 页号
     * @param size 页大小
     * @param example 查询条件对象
     * @return 分页实体对象
     */
    @Override
    public PageVo<T> findPage(Integer page, Integer size, Example example){
        PageInfo<T> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> mapper.selectByExample(example));
        return new PageVo<T>(pageInfo);
    }

    /**
     * 创建查询条件 CreateCriteria
     * @param clazz 实体类
     * @return Criteria<T>
     */
    @Override
    public Criteria<T> createCriteria(Class<T> clazz){
        return new Criteria<T>(clazz);
    }

    /**
     * 根据Criteria（支持lambda表达式）条件查询列表
     * @param criteria （支持lambda表达式）
     * @return List<T>
     */
    @Override
    public List<T> findByWhere(Criteria<T> criteria) {
        return this.findByWhere(this.getExample(criteria));
    }

    /**
     * 根据Criteria（支持lambda表达式）条件分页查询列表
     * @param page 当前页
     * @param size 每页数量
     * @param criteria 支持lambda表达式
     * @return PageVo<T>
     */
    @Override
    public PageVo<T> findPage(Integer page, Integer size, Criteria<T> criteria) {
        return this.findPage(page,size,this.getExample(criteria));
    }

    /**
     * 创建 Example
     * @param criteria com.small.site.ibase.Criteria
     * @return tk.mybatis.mapper.entity.Example
     */
    private Example getExample(Criteria<T> criteria) {
        Example example = new Example(criteria.getClazz());
        this.setCriteria(example.createCriteria(),criteria);
        if (criteria.isAnd() && !criteria.getCriteriaAndList().isEmpty()){
            for (Criteria<T> criteria1 : criteria.getCriteriaAndList()) {
                example.and(this.setCriteria(example.createCriteria(), criteria1));
            }
        }
        if (criteria.isOr() && !criteria.getCriteriaOrList().isEmpty()){
            for (Criteria<T> criteria2 : criteria.getCriteriaOrList()) {
                example.and(this.setCriteria(example.createCriteria(), criteria2));
            }
        }
        String orderBy = criteria.getOrderBy();
        if (orderBy != null && !"".equals(orderBy)) {
            if ("desc".equals(criteria.order())){
                example.orderBy(orderBy).desc();
            }else {
                example.orderBy(orderBy).asc();
            }
        }
        return example;
    }

    /**
     * 设置条件
     * @param exampleCriteria tk.mybatis.mapper.entity.Example.Criteria
     * @param criteria com.small.site.ibase.Criteria
     * @return Example.Criteria
     */
    private Example.Criteria setCriteria(Example.Criteria exampleCriteria, Criteria<T> criteria){
        Map<String,Object> params = criteria.getParams();
        params.forEach((k,v) -> {
            if (k != null && !"".equals(k)){
                String[] s = k.split("_");
                if (s.length == 2){
                    if ("andEqualTo".equals(s[1])){
                        exampleCriteria.andEqualTo(s[0],v);
                    }
                    if ("orEqualTo".equals(s[1])){
                        exampleCriteria.orEqualTo(s[0],v);
                    }
                    if ("andLike".equals(s[1])){
                        exampleCriteria.andLike(s[0],String.valueOf(v));
                    }
                    if ("orLike".equals(s[1])){
                        exampleCriteria.orLike(s[0],String.valueOf(v));
                    }
                    if ("andGreaterThan".equals(s[1])){
                        exampleCriteria.andGreaterThan(s[0],v);
                    }
                    if ("orGreaterThan".equals(s[1])){
                        exampleCriteria.orGreaterThan(s[0],v);
                    }
                    if ("andGreaterThanOrEqualTo".equals(s[1])){
                        exampleCriteria.andGreaterThanOrEqualTo(s[0],v);
                    }
                    if ("orGreaterThanOrEqualTo".equals(s[1])){
                        exampleCriteria.orGreaterThanOrEqualTo(s[0],v);
                    }
                    if ("andLessThan".equals(s[1])){
                        exampleCriteria.andLessThan(s[0],v);
                    }
                    if ("orLessThan".equals(s[1])){
                        exampleCriteria.orLessThan(s[0],v);
                    }
                    if ("andLessThanOrEqualTo".equals(s[1])){
                        exampleCriteria.andLessThanOrEqualTo(s[0],v);
                    }
                    if ("orLessThanOrEqualTo".equals(s[1])){
                        exampleCriteria.orLessThanOrEqualTo(s[0],v);
                    }
                }
            }
        });
        params.clear();
        return exampleCriteria;
    }

    /**
     * 新增
     * @param t 实体对象
     */
    @Override
    public int insert(T t) {
        return mapper.insertSelective(t);
    }

    /**
     * 批量新增（注意：这里主键 id 必须为自增的，否则报错没有默认值）
     * @param list 实体对象
     */
    @Override
    public int insertBatch(List<T> list){
        if (list != null && list.size() > 0){
            return mySqlMapper.insertList(list);
        }
        return 0;
    }

    /**
     * 批量新增（大数据批量新增）
     * @param list 实体对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertBigBatch(List<T> list) {
        /*if (list.size() <= 500){
            mySqlMapper.insertList(list);
        }else {
            for (int i = 0,size = list.size(); i < size; i++) {
                if (i%500 == 0){// 每500条提交一次防止内存溢出
                    mySqlMapper.insertList(list.subList(i,i+500));
                }
            }
        }*/
        SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
        for (int i = 0,size = list.size(); i < size; i++) {
            mapper.insertSelective(list.get(i));
            if(i%1000==999) { // 每1000条提交一次防止内存溢出
                sqlSession.commit();
                sqlSession.clearCache();
            }
        }
        sqlSession.commit();
        sqlSession.clearCache();
        return list.size();
    }

    /**
     * 根据主键更新
     * @param t 实体对象
     */
    @Override
    public int updateById(T t) {
        return mapper.updateByPrimaryKeySelective(t);
    }

    /**
     * 根据实体对象更新
     * @param t 实体对象
     * @param example example
     */
    @Override
    public int update(T t,Example example) {
        return mapper.updateByExample(t,example);
    }

    /**
     * 根据实体对象更新
     * @param t 实体
     * @param criteria 支持lambda表达式
     */
    @Override
    public int update(T t,Criteria<T> criteria) {
        return mapper.updateByExample(t,this.getExample(criteria));
    }

    /**
     * 条件删除
     * @param t 实体对象
     * @return int
     */
    @Override
    public int deleteByWhere(T t) {
        return mapper.delete(t);
    }

    /**
     * 条件删除
     * @param example example
     * @return int
     */
    @Override
    public int deleteByWhere(Example example) {
        return mapper.deleteByExample(example);
    }

    /**
     * 条件删除 criteria
     * @param criteria 支持lambda表达式
     * @return int
     */
    @Override
    public int deleteByWhere(Criteria<T> criteria) {
        return mapper.deleteByExample(this.getExample(criteria));
    }

    /**
     * 主键删除
     * @param id 主键
     */
    @Override
    public int deleteById(Serializable id) {
        return mapper.deleteByPrimaryKey(id);
    }

    /**
     * 批量删除
     * @param ids 主键集合
     */
    @Override
    public void deleteByIds(Serializable[] ids) {
        if (ids != null && ids.length > 0) {
            for (Serializable id : ids) {
                mapper.deleteByPrimaryKey(id);
            }
        }
    }

    /**
     * count 统计
     * @param t 实体
     * @return int
     */
    @Override
    public int count(T t) {
        return mapper.selectCount(t);
    }

    /**
     * count 统计
     * @param example example
     * @return int
     */
    @Override
    public int count(Example example) {
        return mapper.selectCountByExample(example);
    }

    /**
     * count 统计
     * @param criteria 支持lambda表达式
     * @return int
     */
    @Override
    public int count(Criteria<T> criteria) {
        return mapper.selectCountByExample(this.getExample(criteria));
    }
}
